from typing import Optional

from django.core.cache import cache as dj_cache
from django.utils.translation import gettext as _

from apps.app_tx_meeting.models import TxMeetingConfig


class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super().__call__(*args, **kwargs)

        return cls._instance


class TxMeetingConfigManager(metaclass=Singleton):
    ConfigName = TxMeetingConfig.ConfigName
    CACHE_KEY = 'app_tx_meeting_configs_cache'

    @staticmethod
    def get_configs_no_cache(remove_invalid: bool = False):
        qs = TxMeetingConfig.objects.all().values('name', 'value')
        configs = {}
        invalid_names = []
        for cfg in qs:
            name = cfg['name']
            if name in TxMeetingConfig.ConfigName.values:
                configs[cfg['name']] = cfg['value']
            else:
                invalid_names.append(name)

        if remove_invalid and invalid_names:
            TxMeetingConfig.objects.filter(name__in=invalid_names).delete()

        # 缺少配置
        if len(configs) < len(TxMeetingConfig.ConfigName.values):
            for name in TxMeetingConfig.ConfigName.values:
                if name not in configs:
                    def_values = TxMeetingConfig.value_defaults[name]
                    if isinstance(def_values, dict):
                        value = def_values.get('value', '')
                        remark = def_values.get('remark', '')
                    else:
                        value = def_values
                        remark = ''

                    obj, created = TxMeetingConfig.objects.get_or_create(
                        name=name, defaults={'value': value, 'remark': remark})
                    configs[name] = obj.value

        return configs

    @staticmethod
    def get_configs():
        cache_key = TxMeetingConfigManager.CACHE_KEY
        configs = dj_cache.get(cache_key)
        if configs:
            return configs

        configs = TxMeetingConfigManager.get_configs_no_cache(remove_invalid=False)
        dj_cache.set(cache_key, configs, timeout=120)
        return configs

    @staticmethod
    def clear_cache():
        dj_cache.delete(TxMeetingConfigManager.CACHE_KEY)

    def get(self, name: str):
        """
        查询参数
        """
        if name not in TxMeetingConfig.ConfigName.values:
            raise Exception(_('未知的AAI参数'))

        configs = self.get_configs()
        return configs[name]

    def set(self, name: str, value: str, remark: str = ''):
        if name not in TxMeetingConfig.ConfigName.values:
            raise Exception(_('未知的AAI参数'))

        obj, created = TxMeetingConfig.objects.update_or_create(
            name=name, defaults={'value': value, 'remark': remark})
        self.clear_cache()
        return obj, created

    @staticmethod
    def get_config_obj(name: str) -> Optional[TxMeetingConfig]:
        return TxMeetingConfig.objects.filter(name=name).first()

    @staticmethod
    def to_bool(val: str) -> Optional[bool]:
        if isinstance(val, bool):
            return val

        val = val.lower()
        if val == 'true':
            return True
        elif val == 'false':
            return False

        return None


tx_meeting_configs = TxMeetingConfigManager()
